import pandas as pd
from infer_format import BoundingBox


def check_hole_(boxes):
    min_x, min_y, max_x, max_y = int(boxes[0][2][0]), int(boxes[0][2][1]), int(boxes[0][2][2]), int(boxes[0][2][3])
    for cls, conf, xyxy in boxes:
        class_index, x_min, y_min, x_max, y_max, confidence = cls, xyxy[0], xyxy[1], xyxy[2], xyxy[3], conf
        # print("point: ", x_min, y_min, x_max, y_max, confidence)
        min_x = min(min_x, x_min)
        min_y = min(min_y, y_min)
        max_x = max(max_x, x_max)
        max_y = max(max_y, y_max)
    # print("-------", min_x, min_y, max_x, max_y)
    # print("-------", max_y-min_y, max_x-min_x, max_x-min_x-(max_y-min_y))
    # print("处理之前长度：", len(boxes))
    # print((max_y-min_y), (max_x-min_x), abs((max_y-min_y)-(max_x-min_x)), abs((max_y-min_y)-(max_x-min_x)) >= 20)
    if abs((max_y-min_y)-(max_x-min_x)) >= 20:
        # 存在错误识别的点位
        # print("   ", max_x, abs_value)
        thre_v = max_x - (max_y - min_y)-20
        save_boxs = []
        for box_ in range(len(boxes)):
            min_x, min_y, max_x, max_y = int(boxes[box_][2][0]), int(boxes[box_][2][1]), int(boxes[box_][2][2]), int(boxes[box_][2][3])
            # print(thre_v, "----------- ", min_x, min_y, max_x, max_y)
            if min_x >= thre_v:
                save_boxs.append(box_)
        boxes = [boxes[b_] for b_ in save_boxs]
    # print("处理之后长度：", len(boxes))
    return boxes


def trans_matrix(boxes):
    """
    识别点位转换为矩阵
    :param boxes:
    :return:
    """
    # 定义矩阵大小
    N = 6
    # 初始化一个N x N的DataFrame，所有元素都是0（没有子）
    holeboard = pd.DataFrame([[0] * N for _ in range(N)])
    # print("holeboard: ",holeboard)
    min_x, min_y, max_x, max_y = int(boxes[0][2][0]), int(boxes[0][2][1]), int(boxes[0][2][2]), int(boxes[0][2][3])
    # 将预测的矩形框结果转换为1和0的DataFrame矩阵
    # new_boxes = []
    # 假设棋盘格子的大小和间距
    cell_size = 19.5  # 棋盘格子大小为19x19
    spacing = 9.5  # 棋盘格子间距为9
    for cls, conf, xyxy in boxes:
        class_index, x_min, y_min, x_max, y_max, confidence = cls, xyxy[0], xyxy[1], xyxy[2], xyxy[3], conf
        # print("point: ", x_min, y_min, x_max, y_max, confidence)
        min_x = min(min_x, x_min)
        min_y = min(min_y, y_min)
        max_x = max(max_x, x_max)
        max_y = max(max_y, y_max)
    # print("-------", min_x, min_y, max_x, max_y)
    # print("-------", max_y-min_y, max_x-min_x, max_x-min_x-(max_y-min_y))
    print("处理之前长度：", len(boxes))
    # print((max_y-min_y), (max_x-min_x), abs((max_y-min_y)-(max_x-min_x)), abs((max_y-min_y)-(max_x-min_x)) >= 20)
    if abs((max_y-min_y)-(max_x-min_x)) >= 20:
        # 存在错误识别的点位
        abs_value = abs((max_y - min_y) - (max_x - min_x))
        # print("   ", max_x, abs_value)
        thre_v = max_x-(max_y - min_y)-20
        save_boxs = []
        for box_ in range(len(boxes)):
            min_x, min_y, max_x, max_y = int(boxes[box_][2][0]), int(boxes[box_][2][1]), int(boxes[box_][2][2]), int(boxes[box_][2][3])
            # print(thre_v, "----------- ", min_x, min_y, max_x, max_y)
            if min_x >= thre_v:
                save_boxs.append(box_)
        boxes = [boxes[b_] for b_ in save_boxs]
    print("处理之后长度：", len(boxes))
    # 将左上角的点作为平移偏移量
    offset_x, offset_y = min_x, min_y

    # 将预测的矩形框结果转换为1和0的DataFrame矩阵
    for cls, conf, xyxy in boxes:
        class_index, x_min, y_min, x_max, y_max, confidence = cls, xyxy[0], xyxy[1], xyxy[2], xyxy[3], conf
        # print("变换前：", x_min, y_min, x_max, y_max)
        # 平移点位
        x_max = (x_max - offset_x + spacing / 2)
        y_max = (y_max - offset_y + spacing / 2)
        # 缩放
        # 修改，由于部分孔洞画框变大，需计算 例如值为4.02的情况下  位置取值应该为3.5-4.5之间，取3
        x_max_re = x_max / (cell_size + spacing)
        x_max_resize = int(x_max_re)
        if x_max_re - x_max_resize <= 0.3:
            x_max_resize = int(x_max_resize - 1)

        y_max_re = y_max / (cell_size + spacing)
        y_max_resize = int(y_max_re)
        if y_max_re - y_max_resize <= 0.3:
            y_max_resize = int(y_max_resize - 1)

        # print("取整前x：", x_max / (cell_size + spacing), x_max_resize)
        # print("取整前y：", y_max / (cell_size + spacing), y_max_resize)
        # print("变换后：", x_max, y_max, x_max_resize, y_max_resize)
        if y_max_resize <= 5 and x_max_resize <= 5:
            # print("y_max_resize, x_max_resize: ", y_max_resize, x_max_resize)
            holeboard.iloc[y_max_resize, x_max_resize] = 1
    # 打印输出DataFrame矩阵
    # print("对孔前:")
    # print(holeboard)
    return holeboard


def matrix_translation(holeboard):
    """
    矩阵变换
    :param holeboard:
    :return:
    """
    # 将DataFrame转换为NumPy数组
    array = holeboard.values
    import numpy as np

    # 顺时针旋转90度
    rotated_array = np.rot90(array, -1)

    # 上下翻转
    flipped_array = np.flipud(rotated_array)

    # 将NumPy数组转换回DataFrame
    rotated_df = pd.DataFrame(rotated_array)
    flipped_df = pd.DataFrame(flipped_array)

    # 打印变换后的矩阵
    # print("顺时针旋转90度:")
    # print(rotated_df)
    # #
    # print("对孔后:")
    # print(flipped_df)
    return flipped_df


def convert_digit(flipped_df):
    """
    转换数字
    :param flipped_df:
    :return:
    """

    # 将DataFrame按行拼接成一个列表
    flattened_list = flipped_df.values.flatten().tolist()

    BOX_ARGUMENT = [-1, -1, 19, 18, 17, -1,
                    -1, -1, 16, 15, -1, 14,
                    13, 12, 11, 10, 9, 8,
                    7, 6, 5, 4, 3, 2,
                    1, -1, 0, -2, -1, -2,
                    -1, -2, -2, -2, -2, -1]

    # 根据标准矩阵规则进行处理
    result = [flattened_list[i] for i in range(len(BOX_ARGUMENT)) if BOX_ARGUMENT[i] != -1 and BOX_ARGUMENT[i] != -2]
    checks_result = [flattened_list[i] for i in range(len(BOX_ARGUMENT)) if BOX_ARGUMENT[i] == -2]
    # print("孔洞识别数值位-串：", result)
    # print("孔洞识别校验码-串：", checks_result)
    # 转换为二进制数并合成整数
    binary_number = list_to_binary(result)
    # print("转换二进制：", binary_number)
    check_no = []
    for i in range(6):
        # print("校验位：", binary_number, 5 - i)
        check_no.append(GetChecksumme(binary_number, 5 - i))

    # print(f"通过数值推出校验码", check_no)
    # print("孔洞识别孔位转换数值位:", binary_number)
    checks_no = hex(CalcCRC16(int2hex(binary_number)) >> 12)[2:].upper()
    # print(f"孔洞识别校验码", checks_no)
    return str(binary_number), checks_no, checks_result == check_no


def plate_status_check(plate_no, plate_check_no):
    """
    公式转换校验数字与图像识别校验数字一致性比对结果
    :param plate_no:
    :param plate_check_no:
    :return:
    """
    if len(plate_no) != 6:
        return False
    if not plate_no.isdigit():
        return False
    return hex(CalcCRC16(int2hex(int(plate_no))) >> 12)[2:].upper() == plate_check_no


def list_to_binary(nums):
    binary_string = ''.join(map(str, nums))
    # print("binary_string: ", binary_string)
    decimal_value = int(binary_string, 2)
    return decimal_value


# 校验码
def GetChecksumme(number, ChechsummenNr):
    Checksumme = [False for i in range(26)]
    # print("Checksumme1 : ", Checksumme)
    Result = "--"
    DoCoZahl = number
    # for i in range(26):
    #     Checksumme[i] = False
    # print("Checksumme2 : ", Checksumme)
    Z1 = 20
    while DoCoZahl > 0:
        if DoCoZahl % 2 == 0:
            Z1 = Z1 - 1
            Checksumme[Z1] = False
        if DoCoZahl % 2 == 1:
            Z1 = Z1 - 1
            Checksumme[Z1] = True
        DoCoZahl = DoCoZahl // 2
    # print("DoCoZahl=", Z1, Checksumme[Z1], Checksumme)
    first = True
    while first or not Z1 >= 19:
        first = False
        Z1 = -1
        Z1 = Z1 + 1
        while not (Checksumme[Z1] or (Z1 > 19)):
            Z1 = Z1 + 1
        # print("find Z1=", Z1)
        if Z1 <= 19:
            Checksumme[Z1] = not Checksumme[Z1]
            Checksumme[Z1 + 4] = not Checksumme[Z1 + 4]
            Checksumme[Z1 + 5] = not Checksumme[Z1 + 5]
            Checksumme[Z1 + 6] = not Checksumme[Z1 + 6]
            # print("Checksumme=", Checksumme)
    if ChechsummenNr == 0:
        Result = Checksumme[25]
    elif ChechsummenNr == 1:
        Result = Checksumme[24]
    elif ChechsummenNr == 2:
        Result = Checksumme[23]
    elif ChechsummenNr == 3:
        Result = Checksumme[22]
    elif ChechsummenNr == 4:
        Result = Checksumme[21]
    elif ChechsummenNr == 5:
        Result = Checksumme[20]
    # print("Result=", Result, Checksumme)
    return 1 if Result else 0


TableCRC16 = [
    0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
    0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
    0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
    0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
    0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
    0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
    0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
    0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
    0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
    0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
    0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
    0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
    0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
    0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
    0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
    0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
    0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
    0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
    0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
    0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
    0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
    0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
    0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
    0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
    0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
    0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
    0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
    0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
    0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
    0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
    0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
    0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
]


def CalcCRC16(buf_bytes):
    # buf_bytes = bytes(reversed(buf_bytes))
    # print("buf_bytes=", buf_bytes.hex())
    crc = 0xffff
    for index in range(0, len(buf_bytes), 1):
        crc = (crc >> 8) ^ TableCRC16[(crc ^ buf_bytes[index]) & 0xff]
        # print(index, "crc=", crc)
    return crc


def objectes(boxes, type='hole'):
    res = []
    if 'hole' == type:
        for cls, conf, xyxy in boxes:
            res.append(BoundingBox("hole", conf, xyxy[0], xyxy[1], xyxy[2], xyxy[3]))
    else:
        # print("识别数字...")
        for title, conf, xyxy in boxes:
            res.append(BoundingBox(title, conf, xyxy[0], xyxy[1], xyxy[2], xyxy[3]))
    return res


def int2hex(num):
    # print(num, "  ", int.to_bytes(num, 4, byteorder="little"))
    return int.to_bytes(num, 4, byteorder="little")
